const fs = require('fs')
const path = require('path')
const CodeGen = require('./code_gen');

class ViewModelGen extends CodeGen {
  genHeader(json) {
    const desc = json.desc || "";
    const clsType = json.name;
    const clsName = this.toClassName(json.name);
    const objName = this.toObjName(json.name);
    const uclsName = clsName.toUpperCase();
    const vmClsName = this.toViewModelClassName(json.name);
    const vmClsType = this.toViewModelClassType(json.name);
    const header = path.basename(json.header);

    let result = `
/*This file is generated by code generator*/

#include "${header}"
#include "mvvm/base/view_model.h"

#ifndef TK_${uclsName}_VIEW_MODEL_H
#define TK_${uclsName}_VIEW_MODEL_H

BEGIN_C_DECLS
/**
 * @class ${vmClsType}
 *
 * view model of ${clsName}
 *
 */
typedef struct _${vmClsType} {
  view_model_t view_model;

  /*model object*/
  ${clsType}* ${objName};
} ${vmClsType};

/**
 * @method ${vmClsName}_create
 * 创建${clsName} view model对象。
 *
 * @annotation ["constructor"]
 * @param {navigator_request_t*} req 请求参数。
 *
 * @return {view_model_t} 返回view_model_t对象。
 */
view_model_t* ${vmClsName}_create(navigator_request_t* req);

/**
 * @method ${vmClsName}_create_with
 * 创建${clsName} view model对象。
 *
 * @annotation ["constructor"]
 * @param {${clsType}*}  ${objName} ${clsName}对象。
 *
 * @return {view_model_t} 返回view_model_t对象。
 */
view_model_t* ${vmClsName}_create_with(${clsType}* ${objName});

/**
 * @method ${vmClsName}_attach
 * 关联到${clsName}对象。
 *
 * @param {view_model_t*} view_model view_model对象。
 * @param {${clsType}*} ${clsName} ${clsName}对象。
 *
 * @return {ret_t} 返回RET_OK表示成功，否则表示失败。
 */
ret_t ${vmClsName}_attach(view_model_t* vm, ${clsType}* ${objName});

END_C_DECLS

#endif /*TK_${uclsName}_VIEW_MODEL_H*/
`

    return result;
  }

  genContent(json) {
    const desc = json.desc || "";
    const clsType = json.name;
    const objName = this.toObjName(json.name);
    const clsName = this.toClassName(json.name);
    const uclsName = clsName.toUpperCase();
    const setPropsDispatch = this.genSetPropDispatch(json);
    const getPropsDispatch = this.genGetPropDispatch(json);
    const canExecDispatch = this.genCanExecDispatch(json);
    const execDispatch = this.genExecDispatch(json);
    const constructor = this.genConstructor(json);
    const destructor = this.genDestructor(json);
    const forwardEvents = this.genForwardEvents(json);
    const offEvents = this.genOffEvents(json);
    const vmClsName = this.toViewModelClassName(json.name);
    const vmClsType = this.toViewModelClassType(json.name);

    let result = `
/*This file is generated by code generator*/

#include "tkc/mem.h"
#include "tkc/utils.h"
#include "mvvm/base/utils.h"
#include "${vmClsName}.h"

static ret_t ${vmClsName}_set_prop(tk_object_t* obj, const char* name, const value_t* v) {
  ${clsType}* ${objName} = ((${vmClsType}*)(obj))->${objName};

${setPropsDispatch}
  
  return RET_NOT_FOUND;
}


static ret_t ${vmClsName}_get_prop(tk_object_t* obj, const char* name, value_t* v) {
  ${clsType}* ${objName} = ((${vmClsType}*)(obj))->${objName};

${getPropsDispatch}

  return RET_NOT_FOUND;
}


static bool_t ${vmClsName}_can_exec(tk_object_t* obj, const char* name, const char* args) {
${canExecDispatch}
  return FALSE;
}

static ret_t ${vmClsName}_exec(tk_object_t* obj, const char* name, const char* args) {
${execDispatch}
  return RET_NOT_FOUND;
}

static ret_t ${vmClsName}_on_destroy(tk_object_t* obj) {
  ${vmClsType}* vm = (${vmClsType}*)(obj);
  return_value_if_fail(vm != NULL, RET_BAD_PARAMS);

  ${offEvents}
  ${destructor}(vm->${objName});

  return view_model_deinit(VIEW_MODEL(obj));
}

static const object_vtable_t s_${vmClsName}_vtable = {
  .type = "${vmClsType}",
  .desc = "${vmClsType}",
  .size = sizeof(${vmClsType}),
  .is_collection = FALSE,
  .on_destroy = ${vmClsName}_on_destroy,
  .compare = NULL,
  .get_prop = ${vmClsName}_get_prop,
  .set_prop = ${vmClsName}_set_prop,
  .remove_prop = NULL,
  .foreach_prop = NULL,
  .clear_props = NULL,
  .find_prop = NULL,
  .find_props = NULL,
  .can_exec = ${vmClsName}_can_exec,
  .exec = ${vmClsName}_exec,
  .clone = NULL
};

view_model_t* ${vmClsName}_create_with(${clsType}* ${objName}) {
  tk_object_t* obj = tk_object_create(&s_${vmClsName}_vtable);
  view_model_t* vm = view_model_init(VIEW_MODEL(obj));
  ${vmClsType}* ${vmClsName} = (${vmClsType}*)(vm);

  return_value_if_fail(vm != NULL, NULL);

  ${vmClsName}->${objName} = ${objName};
  ${forwardEvents}

  return vm;
}

ret_t ${vmClsName}_attach(view_model_t* vm, ${clsType}* ${objName}) {
  ${vmClsType}* ${vmClsName} = (${vmClsType}*)(vm);
  return_value_if_fail(vm != NULL, RET_BAD_PARAMS);

  ${vmClsName}->${objName} = ${objName};

  return RET_OK;
}

view_model_t* ${vmClsName}_create(navigator_request_t* req) {
  ${clsType}* ${objName} = ${constructor};
  return_value_if_fail(${objName} != NULL, NULL);

  return ${vmClsName}_create_with(${objName});
}
`;

    return result;
  }

  filter(json) {
    console.log(this.underLineName('RoomSettings'));
    return json.filter(iter => {
      return this.isModel(iter) && !this.isCollectionModel(iter)
    });
  }

  static run(filename) {
    const gen = new ViewModelGen();
    gen.genFile(filename);
  }
}

if (process.argv.length < 3) {
  console.log(`Usage: node index.js idl.json`);
  process.exit(0);
}

ViewModelGen.run(process.argv[2]);
